package entity.invoke;

import entity.pojo.Book;
import entity.pojo.Student;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//反射获取类的四种方式
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {

        //方式一：forName获得
        Class c1 = Class.forName("entity.pojo.Book");
        Class c2 = Class.forName("entity.pojo.Book");

        //一个类在内存中只有一个Class对象
        //一个类被加载后，类的整个结构都会被封装在Class对象中
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());


        Student student = new Student();

        //方式二：通过对象获得
        Class cs1 = student.getClass();
        //方式三：通过类名.class获得
        Class cs2 = Student.class;
        System.out.println(cs1.hashCode());
        System.out.println(cs2.hashCode());

        //方式四:基本内置类型的包装类都有一个type属性
        Class i = Integer.TYPE;
        System.out.println(i);

//        Field[] fields=c1.getFields(); //只能获取public的
        Field[] fields = c1.getDeclaredFields();

        for (Field field : fields) {
            System.out.println(field);
        }

        Method[] methods = cs1.getMethods();//获取本类和父类全部public

//        Method[] methods=cs1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        Method setMethod = cs1.getDeclaredMethod("setName", String.class);
        Method getMethod = cs1.getMethod("getName");
        System.out.println(setMethod);
        System.out.println(getMethod);

        //通过反射构造一个对象
        Book book = (Book) c1.newInstance();

        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, Double.class, Student.class);
        Book book1 = (Book) constructor.newInstance("西游记", 67.00, new Student());
        System.out.println(book1);


        //invoke:激活的意思 (对象，“方法的值”)
        Book book2 = (Book) c1.newInstance();
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(book2, "红楼梦");
        System.out.println(book2.getName());

        Field setFile = c1.getDeclaredField("name");
        setFile.setAccessible(true);//关闭程序的安全检测，就可以访问私有属性了
        setFile.set(book2, "红楼梦2");
        System.out.println(book2.getName());


//        Book b=new Book();
//        Class<?> clazz = Class.forName("entity.pojo.Book");
//        Method m = clazz.getDeclaredMethod("setName", String.class);
//        m.invoke(b,"三国");
//        System.out.println(b);


        /*
        需求:

        外面的人想要大明星唱一首歌
        1.获取代理的对象
                代理对象 = Proxyuti1.createProxy(大明星的对象):再调用代理的唱歌方法2.
                代理对象.唱歌的方法("只因你太美");
         */

        //1.获取代理的对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);
        //2.调用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);
        System.out.println(proxy.dance());

    }
}
